﻿#include "include/flutter_blue_plus_win/flutter_blue_plugin.h"
#include "event_stream_handler.h"
#include "flutter_blue_utils.h"
#include "flutter_blue_device_agent.h"
#include "flutter_blue_event_handler.h"
#include "flutter_blue_help.h"
// This must be included before many other Windows headers.
#include <windows.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Storage.Streams.h>
#include <winrt/Windows.Devices.Radios.h>
#include <winrt/Windows.Devices.Bluetooth.h>
#include <winrt/Windows.Devices.Bluetooth.Advertisement.h>
#include <winrt/Windows.Devices.Bluetooth.GenericAttributeProfile.h>
#include <winrt/Windows.Devices.Enumeration.h>
#include <winrt/Windows.UI.Core.h>

#include <flutter/encodable_value.h>
#include <flutter/method_channel.h>
#include <flutter/basic_message_channel.h>
#include <flutter/event_channel.h>
#include <flutter/event_stream_handler_functions.h>
#include <flutter/plugin_registrar_windows.h>
#include <flutter/standard_method_codec.h>
#include <flutter/standard_message_codec.h>

#include <map>
#include <memory>
#include <sstream>
#include <algorithm>
#include <iomanip>

using namespace winrt;
using namespace Windows::Devices::Bluetooth;
using namespace Windows::UI::Core;
const winrt::guid CMSN_DATA_STREAM_SERVICE_UUID = { 0x0D740001, 0xD26F, 0x4DBB, {0x95, 0xE8, 0xA4, 0xF5, 0xC5, 0x5C, 0x57, 0xA9} };
const winrt::guid BSTAR_DATA_STREAM_SERVICE_UUID = { 0x6E400001, 0xB5A3, 0xF393, {0xE0, 0xA9, 0xE5, 0x0E, 0x24, 0xDC, 0xCA, 0x9E} };
const winrt::guid MORPHEUS_DATA_STREAM_SERVICE_UUID = { 0x4DE5A20C, 0x0001, 0xAE02, {0xBF, 0x63, 0x02, 0x42, 0xAC, 0x13, 0x00, 0x02} };

const std::string MORPHEUS_UUID_STRING = "4de5a20c-0001-ae02-bf63-0242ac130002";


namespace {

	using namespace winrt;
	using namespace winrt::Windows::Foundation;
	using namespace winrt::Windows::Foundation::Collections;
	using namespace winrt::Windows::Storage::Streams;
	using namespace winrt::Windows::Devices::Radios;
	using namespace winrt::Windows::Devices::Bluetooth;
	using namespace winrt::Windows::Devices::Bluetooth::Advertisement;
	using namespace winrt::Windows::Devices::Bluetooth::GenericAttributeProfile;
	using namespace winrt::Windows::Devices::Enumeration;

	using flutter::EncodableValue;
	using flutter::EncodableMap;
	// 定义一个类型别名，用于表示 MaxPduSizeChanged 的回调函数签名
	using MaxPduSizeChangedCallback = std::function<void(int)>;


	class FlutterBluePlugin : public flutter::Plugin {
	public:
		static void RegisterWithRegistrar(flutter::PluginRegistrarWindows* registrar);

		// 构造函数
		FlutterBluePlugin() {
			// 创建 FlutterEventHandler 实例，并传递回调函数
			event_handler_ = std::make_unique<FlutterEventHandler>([this](const flutter::EncodableValue& result) {
				sendMessageConnector(result);
				}, [this](const std::string result) {
					logToFlutter(result);
					});
			// 创建 FlutterBleHelp 实例，并传递回调函数
			ble_help_ = std::make_unique<FlutterBleHelp>([this](const flutter::EncodableValue& result) {
				sendMessageConnector(result);
				}, [this](const std::string result) {
					logToFlutter(result);
					});
				InitializeAsync();
		}

	private:
		static inline flutter::BinaryMessenger* binaryMessenger;
		std::unique_ptr<FlutterEventHandler> event_handler_;
		std::unique_ptr<FlutterBleHelp> ble_help_;
		winrt::fire_and_forget InitializeAsync();

		// 发送消息到 Dart 的线程安全方法  不知道怎么实现
		void sendMessageConnector(const flutter::EncodableValue& message);

		void logToFlutter(std::string message);

		// Called when a method is called on this plugin's channel from Dart.
		void HandleMethodCall(
			const flutter::MethodCall <flutter::EncodableValue>& method_call,
			std::unique_ptr <flutter::MethodResult<flutter::EncodableValue>> result);


		std::unique_ptr <flutter::BasicMessageChannel<EncodableValue>> message_connector_;



		Radio bluetoothRadio{ nullptr };
		//是否支持
		BluetoothAdapter bluetoothAdapter = nullptr;

		winrt::fire_and_forget FlutterBluePlugin::TurnOnOffBlueAsync(bool turnIsOn);

		void FlutterBluePlugin::OnAdapterStateChanged(Radio sender, IInspectable const&);

	};

	// static
	void FlutterBluePlugin::RegisterWithRegistrar(
		flutter::PluginRegistrarWindows* registrar) {
		// 获取平台线程的任务运行器

		binaryMessenger = registrar->messenger();

		auto method =
			std::make_unique < flutter::MethodChannel < EncodableValue >>(
				binaryMessenger, "flutter_blue_plus_win/method",
				&flutter::StandardMethodCodec::GetInstance());
		auto message_connector_ =
			std::make_unique < flutter::BasicMessageChannel < EncodableValue >>(
				binaryMessenger, "flutter_blue_plus_win/message.connector",
				&flutter::StandardMessageCodec::GetInstance());

		auto event_scan_result =
			std::make_unique < flutter::EventChannel < EncodableValue >>(
				binaryMessenger, "flutter_blue_plus_win/event.scanResult",
				&flutter::StandardMethodCodec::GetInstance());
		auto event_paired_devices =
			std::make_unique < flutter::EventChannel < EncodableValue >>(
				binaryMessenger, "flutter_blue_plus_win/event.pairedDevices",
				&flutter::StandardMethodCodec::GetInstance());

		auto plugin = std::make_unique<FlutterBluePlugin>();

		method->SetMethodCallHandler(
			[plugin_pointer = plugin.get()](const auto& call, auto result) {
				plugin_pointer->HandleMethodCall(call, std::move(result));
			});
		//扫描回调交互
		//plugin->event_handler_->event_scan_handler  = std::make_unique<EventStreamHandler<>>();
		auto _scan_stm_handle = static_cast<StreamHandler <EncodableValue> *>(plugin->event_handler_->event_scan_handler.get());
		std::unique_ptr <StreamHandler<EncodableValue>> _ptr_scan{ _scan_stm_handle };
		event_scan_result->SetStreamHandler(std::move(_ptr_scan));


		//配对回调交互
		//plugin->ble_help_->event_paired_handler = std::make_unique<EventStreamHandler<>>();
		auto _paored_stm_handle = static_cast<StreamHandler <EncodableValue> *>(plugin->ble_help_->event_paired_handler.get());
		std::unique_ptr <StreamHandler<EncodableValue>> _ptr_paired{ _paored_stm_handle };
		event_paired_devices->SetStreamHandler(std::move(_ptr_paired));

		plugin->message_connector_ = std::move(message_connector_);

		registrar->AddPlugin(std::move(plugin));
	}



	winrt::fire_and_forget FlutterBluePlugin::InitializeAsync() {
		// 初始化蓝牙适配器和无线电
		bluetoothAdapter = co_await
			BluetoothAdapter::GetDefaultAsync();
		if (bluetoothAdapter != nullptr) {
			//先获取下状态
			bluetoothRadio = co_await
				bluetoothAdapter.GetRadioAsync();
			// 注册蓝牙开关状态变化事件
			// 使用 std::bind 绑定成员函数和对象实例
			bluetoothRadio.StateChanged(std::bind(&FlutterBluePlugin::OnAdapterStateChanged, this, std::placeholders::_1, std::placeholders::_2));
		}
	}

	//发送消息
	void FlutterBluePlugin::sendMessageConnector(const flutter::EncodableValue& message) {
		if (message_connector_) {
			message_connector_->Send(message, nullptr);
		}
	}

	// 日志 输出的原生
	void FlutterBluePlugin::logToFlutter(std::string message) {
		if (message_connector_) {
			message_connector_->Send(EncodableMap{
					{"type", "log"},
					{"data", message}
				}, nullptr);
		}
	}

	//接收消息
	void FlutterBluePlugin::HandleMethodCall(
		const flutter::MethodCall <flutter::EncodableValue>& method_call,
		std::unique_ptr <flutter::MethodResult<flutter::EncodableValue>> result) {
		auto method_name = method_call.method_name();
		logToFlutter(("HandleMethodCall " + method_name));
		if (method_name.compare("isBluetoothAvailable") == 0) {
			result->Success(EncodableValue(bluetoothRadio && bluetoothRadio.State() == RadioState::On));
		}
		else if (method_name.compare("isSupported") == 0) {
			result->Success(EncodableValue(bluetoothAdapter != nullptr));
		}
		else if (method_name.compare("adapterName") == 0) {
			if (bluetoothRadio != nullptr) {
				result->Success(EncodableValue(winrt::to_string(bluetoothRadio.Name())));
			}
			else {
				result->Error("Bluetooth adapter does not exist");
			}
		}
		else if (method_name.compare("startScanPairedDevices") == 0) {
			ble_help_->StastartScanPairedDevices();
			result->Success(nullptr);

		}
		else if (method_name.compare("stopScanPairedDevices") == 0) {
			ble_help_->StopScanPairedDevices();
			result->Success(nullptr);

		}
		else if (method_name.compare("openBlue") == 0) {
			TurnOnOffBlueAsync(true);
			result->Success(nullptr);
		}
		else if (method_name.compare("offBlue") == 0) {
			TurnOnOffBlueAsync(false);
			result->Success(nullptr);
		}
		else if (method_name.compare("startScan") == 0) {
			event_handler_->StartScan();
			result->Success(nullptr);
		}
		else if (method_name.compare("stopScan") == 0) {
			event_handler_->StopScan();
			result->Success(nullptr);
		}
		else if (method_name.compare("connect") == 0) {
			auto args = std::get<EncodableMap>(*method_call.arguments());
			auto deviceId = std::get<std::string>(args[EncodableValue("deviceId")]);
			event_handler_->ConnectAsync(std::stoull(deviceId));
			result->Success(nullptr);
		}
		else if (method_name.compare("disconnect") == 0) {
			auto args = std::get<EncodableMap>(*method_call.arguments());
			auto deviceId = std::get<std::string>(args[EncodableValue("deviceId")]);
			event_handler_->CleanConnection(std::stoull(deviceId), true);
			result->Success(nullptr);
		}
		else if (method_name.compare("discoverServices") == 0) {
			auto args = std::get<EncodableMap>(*method_call.arguments());
			auto deviceId = std::get<std::string>(args[EncodableValue("deviceId")]);
			auto bluetoothDeviceAgent = event_handler_->GetConnectedDevices(std::stoull(deviceId));
			if (bluetoothDeviceAgent == nullptr) {
				result->Error("IllegalArgument", "Unknown devicesId:" + deviceId);
				return;
			}
			event_handler_->DiscoverServicesAsync(bluetoothDeviceAgent);
			// TODO
			result->Success(nullptr);
		}
		else if (method_name.compare("setNotifiable") == 0) {
			auto args = std::get<EncodableMap>(*method_call.arguments());
			auto deviceId = std::get<std::string>(args[EncodableValue("deviceId")]);
			auto service = std::get<std::string>(args[EncodableValue("service")]);
			auto characteristic = std::get<std::string>(args[EncodableValue("characteristic")]);
			auto bleInputProperty = std::get<std::string>(args[EncodableValue("bleInputProperty")]);
			auto bluetoothDeviceAgent = event_handler_->GetConnectedDevices(std::stoull(deviceId));
			if (bluetoothDeviceAgent == nullptr) {
				result->Error("IllegalArgument", "Unknown devicesId:" + deviceId);
				return;
			}
			event_handler_->SetNotifiableAsync(bluetoothDeviceAgent, service, characteristic, bleInputProperty);
			result->Success(nullptr);
		}
		else if (method_name.compare("requestMtu") == 0) {
			auto args = std::get<EncodableMap>(*method_call.arguments());
			auto deviceId = std::get<std::string>(args[EncodableValue("deviceId")]);
			auto expectedMtu = std::get<int32_t>(args[EncodableValue("expectedMtu")]);
			auto bluetoothDeviceAgent = event_handler_->GetConnectedDevices(std::stoull(deviceId));
			if (bluetoothDeviceAgent == nullptr) {
				result->Error("IllegalArgument", "Unknown devicesId:" + deviceId);
				return;
			}

			event_handler_->RequestMtuAsync(bluetoothDeviceAgent, expectedMtu);
			result->Success(nullptr);
		}
		else if (method_name.compare("readValue") == 0) {
			auto args = std::get<EncodableMap>(*method_call.arguments());
			auto deviceId = std::get<std::string>(args[EncodableValue("deviceId")]);
			auto service = std::get<std::string>(args[EncodableValue("service")]);
			auto characteristic = std::get<std::string>(args[EncodableValue("characteristic")]);
			auto bluetoothDeviceAgent = event_handler_->GetConnectedDevices(std::stoull(deviceId));
			if (bluetoothDeviceAgent == nullptr) {
				result->Error("IllegalArgument", "Unknown devicesId:" + deviceId);
				return;
			}
			event_handler_->ReadValueAsync(bluetoothDeviceAgent, service, characteristic);
			result->Success(nullptr);
		}
		else if (method_name.compare("writeValue") == 0) {
			auto args = std::get<EncodableMap>(*method_call.arguments());
			auto deviceId = std::get<std::string>(args[EncodableValue("deviceId")]);
			auto service = std::get<std::string>(args[EncodableValue("service")]);
			auto characteristic = std::get<std::string>(args[EncodableValue("characteristic")]);
			auto value = std::get < std::vector < uint8_t >>(args[EncodableValue("value")]);
			auto bleOutputProperty = std::get<std::string>(args[EncodableValue("bleOutputProperty")]);
			auto bluetoothDeviceAgent = event_handler_->GetConnectedDevices(std::stoull(deviceId));
			if (bluetoothDeviceAgent == nullptr) {
				result->Error("IllegalArgument", "Unknown devicesId:" + deviceId);
				return;
			}
			event_handler_->WriteValueAsync(bluetoothDeviceAgent, service, characteristic, value, bleOutputProperty);
			result->Success(nullptr);
		}
		else {
			result->NotImplemented();
		}
	}




	//打开蓝牙
	winrt::fire_and_forget FlutterBluePlugin::TurnOnOffBlueAsync(bool turnIsOn) {
		// 检查当前状态是否已经开启
		RadioState toState = turnIsOn ? RadioState::On : RadioState::Off;
		try {
			if (bluetoothRadio.State() != toState) {
				// 尝试将蓝牙无线电设备的状态设置为开启
				RadioAccessStatus
					accessStatus = co_await
					bluetoothRadio.SetStateAsync(toState);
				if (accessStatus == RadioAccessStatus::Allowed) {
					sendMessageConnector(EncodableMap{
							{"type",     "OnOpenBlueResult"},
							{"success",  true},
							{"turnIsOn", turnIsOn},
							{"data",     turnIsOn},
						});
				}
				else {
					sendMessageConnector(EncodableMap{
							{"type",     "OnOpenBlueResult"},
							{"success",  false},
							{"turnIsOn", turnIsOn},
							{"data",     !turnIsOn},
						});
				}
			}
			else {
				sendMessageConnector(EncodableMap{
						{"type",     "OnOpenBlueResult"},
						{"success",  true},
						{"turnIsOn", turnIsOn},
						{"data",     turnIsOn},
					});
			}
		}
		catch (...) {
			sendMessageConnector(EncodableMap{
					{"type",     "OnOpenBlueResult"},
					{"success",  false},
					{"turnIsOn", turnIsOn},
					{"data",     bluetoothRadio.State() == toState},
				});
		}

	}


	//蓝牙开关改变
	void FlutterBluePlugin::OnAdapterStateChanged(Radio sender, IInspectable const&) {
		//sender.IsEnabled()
		//更新状态
		bluetoothRadio = sender;
		std::string state = "unknown";
		if (sender.State() == RadioState::On) {
			state = "on";
		}
		else if (sender.State() == RadioState::Off) {
			state = "off";
		}
		else if (sender.State() == RadioState::Unknown) {
			state = "unknown";
		}
		else if (sender.State() == RadioState::Disabled) {
			state = "disabled";
		}
		sendMessageConnector(EncodableMap{
				{"type",    "OnAdapterStateChanged"},
				{"success", true},
				{"data",    state},
			});
	}





}; // namespace

void FlutterBluePluginRegisterWithRegistrar(
	FlutterDesktopPluginRegistrarRef registrar) {
	FlutterBluePlugin::RegisterWithRegistrar(
		flutter::PluginRegistrarManager::GetInstance()
		->GetRegistrar<flutter::PluginRegistrarWindows>(registrar));
}
